
#include "src/emule/aich_hash_sha1.h"
#include <string.h>
#include "src/config.h"

#define SHA_LITTLE_ENDIAN   1234 /* byte 0 is least significant (i386) */
#define SHA_BIG_ENDIAN      4321 /* byte 0 is most significant (mc68k) */

#define SHA1_BLOCK_SIZE		64
#define SHA1_DIGEST_SIZE	20

#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))

#if defined(LITTLE_ENDIAN)
#define swap_b32(x) ((rotl32((x), 8) & 0x00ff00ff) | (rotl32((x), 24) & 0xff00ff00))
#else
#define swap_b32(x) (x)
#endif

#define SHA1_MASK   (SHA1_BLOCK_SIZE - 1)

/* reverse byte order in 32-bit words   */

#define ch(x,y,z)       (((x) & (y)) ^ (~(x) & (z)))
#define parity(x,y,z)   ((x) ^ (y) ^ (z))
#define maj(x,y,z)      (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))

/* A normal version as set out in the FIPS. This version uses   */
/* partial loop unrolling and is optimised for the Pentium 4    */

#define rnd(f,k) t = a; a = rotl32(a,5) + f(b,c,d) + e + k + w[i]; e = d; d = c; c = rotl32(b, 30); b = t

jellyfish::emule::aich_hash_sha1::aich_hash_sha1()
{
	reset();
}

void jellyfish::emule::aich_hash_sha1::reset()
{
	count[0] = count[1] = 0;
	hash[0] = 0x67452301;
	hash[1] = 0xefcdab89;
	hash[2] = 0x98badcfe;
	hash[3] = 0x10325476;
	hash[4] = 0xc3d2e1f0;
}

void jellyfish::emule::aich_hash_sha1::add( const uint8* pData, uint32 nLength )
{
	const unsigned char* data = (const unsigned char*)pData;

	uint32 pos = (uint32)(count[0] & SHA1_MASK), 
		space = SHA1_BLOCK_SIZE - pos;
	const unsigned char *sp = data;

	if((count[0] += nLength) < nLength)
		++(count[1]);

	while(nLength >= space)     /* tranfer whole blocks while possible  */
	{
		memcpy(((unsigned char*)buffer) + pos, sp, space);
		sp += space; nLength -= space; space = SHA1_BLOCK_SIZE; pos = 0; 
		compile();
	}

	memcpy(((unsigned char*)buffer) + pos, sp, nLength);
}

void jellyfish::emule::aich_hash_sha1::compile()
{
	uint32    w[80], i, a, b, c, d, e, t;

	/* note that words are compiled from the buffer into 32-bit */
	/* words in big-endian order so an order reversal is needed */
	/* here on little endian machines                           */
	for(i = 0; i < SHA1_BLOCK_SIZE / 4; ++i)
		w[i] = swap_b32(buffer[i]);

	for(i = SHA1_BLOCK_SIZE / 4; i < 80; ++i)
		w[i] = rotl32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);

	a = hash[0];
	b = hash[1];
	c = hash[2];
	d = hash[3];
	e = hash[4];

	for(i = 0; i < 20; ++i)
	{
		rnd(ch, 0x5a827999);    
	}

	for(i = 20; i < 40; ++i)
	{
		rnd(parity, 0x6ed9eba1);
	}

	for(i = 40; i < 60; ++i)
	{
		rnd(maj, 0x8f1bbcdc);
	}

	for(i = 60; i < 80; ++i)
	{
		rnd(parity, 0xca62c1d6);
	}

	hash[0] += a; 
	hash[1] += b; 
	hash[2] += c; 
	hash[3] += d; 
	hash[4] += e;
}

#if defined(LITTLE_ENDIAN)
static uint32  mask[4] = 
{   0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff };
static uint32  bits[4] = 
{   0x00000080, 0x00008000, 0x00800000, 0x80000000 };
#else
static uint32  mask[4] = 
{   0x00000000, 0xff000000, 0xffff0000, 0xffffff00 };
static uint32  bits[4] = 
{   0x80000000, 0x00800000, 0x00008000, 0x00000080 };
#endif

void jellyfish::emule::aich_hash_sha1::finish( aich_hash& h )
{
	uint32    i = (uint32)(count[0] & SHA1_MASK);

	buffer[i >> 2] = (buffer[i >> 2] & mask[i & 3]) | bits[i & 3];

	/* we need 9 or more empty positions, one for the padding byte  */
	/* (above) and eight for the length count.  If there is not     */
	/* enough space pad and empty the buffer                        */
	if(i > SHA1_BLOCK_SIZE - 9)
	{
		if(i < 60) buffer[15] = 0;
		compile();
		i = 0;
	}
	else    /* compute a word index for the empty buffer positions  */
		i = (i >> 2) + 1;

	while(i < 14) /* and zero pad all but last two positions      */ 
		buffer[i++] = 0;

	/* assemble the eight byte counter in in big-endian format		*/
	buffer[14] = swap_b32((count[1] << 3) | (count[0] >> 29));
	buffer[15] = swap_b32(count[0] << 3);

	compile();
	get_hash(h);
}

void jellyfish::emule::aich_hash_sha1::get_hash( aich_hash& h )
{
	/* extract the hash value as bytes in case the hash buffer is   */
	/* misaligned for 32-bit words*/
	for(int i = 0; i < SHA1_DIGEST_SIZE; ++i)
		h.get_raw_hash()[i] = (unsigned char)(hash[i >> 2] >> 8 * (~i & 3));
}
